﻿using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Mt.Site.Core.ContentManagement.Entities;
using Mt.Site.Core.DiyContent.Form.Entities;
using Mt.Site.Core.Synchronization.Data;
using System;
using System.Linq;

namespace Mt.Site.Core.Synchronization.ContentManagement
{
    public class ContentDataSoreManager : DomainService, IContentDataSoreManager
    {
        private readonly IRepository<Content, Guid> _contentRepository;
        private readonly IRepository<ContentBody, long> _contentBodyRepository;
        private readonly IRepository<ContentField, long> _contentFieldRepository;

        public ContentDataSoreManager(
            IRepository<Content, Guid> contentRepository,
            IRepository<ContentBody, long> contentBodyRepository,
            IRepository<ContentField, long> contentFieldRepository)
        {
            _contentRepository = contentRepository;
            _contentBodyRepository = contentBodyRepository;
            _contentFieldRepository = contentFieldRepository;
        }

        public Guid CreateContentSync(Content fromEntity, DataProcessingStore input)
        {
            return CreateContentSync2(fromEntity, input.ToTenantId, input.TargetLanguage);
        }

        public Guid UpdateContentSync(Content toEntity, Content fromEntity)
        {
            //与栏目同步类似，但不会像栏目那样可以移位（RelateId不会修改，而栏目的ParentId是可以修改）
            /* 
             * 主动同步：
             * 1. 找到了目标数据，
             *    先查找fromEntity的上级关联数据
             *      1.1  先复制或更新toEntity的上级关联数据
                    1.2  更新toEntity

            */
            var toEntity_RelateId = GetRelateIdForToEntity(fromEntity.RelateId, toEntity.TenantId, toEntity.Language);

            if (toEntity_RelateId != Guid.Empty)    //可以为null
            {
                toEntity.MenuId = fromEntity.MenuId;
                toEntity.AuxiliaryId = fromEntity.AuxiliaryId;
                toEntity.IsDeleted = fromEntity.IsDeleted;
                toEntity.RelateId = toEntity_RelateId;

                EntityMapping(fromEntity, toEntity);

                _contentRepository.Update(toEntity);
                return toEntity.Id;
            }

            return Guid.Empty;   //数据有误
        }


        #region private

        public Guid UnDelete(Content toEntity, Content fromEntity)
        {
            var toEntity_RelateId = GetRelateIdForToEntity(fromEntity.RelateId, toEntity.TenantId, toEntity.Language);

            if (toEntity_RelateId != Guid.Empty)    //可以为null
            {
                if (toEntity.IsDeleted) 
                {
                    EntityMapping(fromEntity, toEntity);
                }

                toEntity.MenuId = fromEntity.MenuId;
                toEntity.AuxiliaryId = fromEntity.AuxiliaryId;
                //手动同步时如果 母站中上级数据被删除了，则不会读取到它的下级数据，也就不会有要同步下级数据，却把上级数据给删除的事儿
                //而自动同步时，母站删除了子站需要复制删除操作
                toEntity.IsDeleted = fromEntity.IsDeleted;
                toEntity.RelateId = toEntity_RelateId;

                _contentRepository.Update(toEntity);
                return toEntity.Id;
            }

            return Guid.Empty;   //数据有误
        }

        private Guid CreateContentSync2(Content fromEntity, int toTenantId, string toLanguage)
        {
            /* 
             *  子站中的目标数据不存在：
             *      查找其上级关联数据（RelateId），
                    * 1. 若存在并未删除则复制目标数据(复制排序号)到其下
                    * 2. 若已删除，则依序把它们恢复过来，再复制目标数据到其下。
                    * 3. 若上级关联数据不存在，则先递归复制上级关联数据
            */

            var toEntity_RelateId = GetRelateIdForToEntity(fromEntity.RelateId, toTenantId, toLanguage);

            if (toEntity_RelateId != Guid.Empty)    //可以为null
            {
                var newEntity = new Content();
                newEntity.Id = Guid.NewGuid();
                newEntity.AutoSynchronous = true;
                newEntity.SourceID = fromEntity.Id;
                newEntity.TenantId = toTenantId;
                newEntity.Language = toLanguage;
                newEntity.MenuId = fromEntity.MenuId;
                newEntity.AuxiliaryId = fromEntity.AuxiliaryId;

                newEntity.RelateId = toEntity_RelateId;
                newEntity.Key = fromEntity.Key;          //内容类型的customKey

                newEntity.Hit = 0;

                EntityMapping(fromEntity, newEntity);

                _contentRepository.Insert(newEntity);

                return newEntity.Id;
            }

            return Guid.Empty;  //数据有误
        }
        private Guid? GetRelateIdForToEntity(Guid? fromEntity_RelateId, int toTenantId, string toLanguage)
        {
            if (fromEntity_RelateId != null)
            {
                var fromEntity_Relate = _contentRepository.FirstOrDefault(fromEntity_RelateId.Value);
                if (fromEntity_Relate != null)
                {
                    var toEntity_Relate = _contentRepository.FirstOrDefault(
                            item => item.AuxiliaryId == fromEntity_Relate.AuxiliaryId && item.TenantId == toTenantId && item.Language == toLanguage);

                    if (toEntity_Relate != null)
                    {
                        //数据即便存在，也可能已经被软删除了，需要恢复（而内容表的虚拟字段不是软删除，所以需要更新）
                        UnDelete(toEntity_Relate, fromEntity_Relate);
                        return toEntity_Relate.Id;
                    }
                    else
                    {
                        //对应的关联数据也不存在时，先复制关联数据（否则数据复制过去也无法使用）
                        return CreateContentSync2(fromEntity_Relate, toTenantId, toLanguage);
                    }
                }
                else
                {
                    //母站中数据（关联id对应的数据）已不存在(数据有误)，导致复制中断。
                    return Guid.Empty;
                }
            }

            return null;
        }

        private void EntityMapping(Content fromEntity, Content toEntity)
        {
            toEntity.IsActive = fromEntity.IsActive;
            toEntity.Title = fromEntity.Title;
            toEntity.Body = fromEntity.Body;
            toEntity.Body2 = fromEntity.Body2;
            toEntity.Order = fromEntity.Order;
            toEntity.PublishTime = fromEntity.PublishTime;
            toEntity.IsHomeRecommend = fromEntity.IsHomeRecommend;
            toEntity.PublishTime = fromEntity.PublishTime;
            toEntity.Time1 = fromEntity.Time1;
            toEntity.Time2 = fromEntity.Time2;
            toEntity.Time3 = fromEntity.Time3;
            toEntity.Time4 = fromEntity.Time4;
            toEntity.Str1 = fromEntity.Str1;
            toEntity.Str2 = fromEntity.Str2;
            toEntity.Str3 = fromEntity.Str3;
            toEntity.Str4 = fromEntity.Str4;
            toEntity.Str5 = fromEntity.Str5;
            toEntity.Str6 = fromEntity.Str6;
            toEntity.Str7 = fromEntity.Str7;
            toEntity.Str8 = fromEntity.Str8;
            toEntity.Str9 = fromEntity.Str9;
            toEntity.Str10 = fromEntity.Str10;
            toEntity.Str11 = fromEntity.Str11;
            toEntity.Str12 = fromEntity.Str12;
            toEntity.Str13 = fromEntity.Str13;
            toEntity.Str14 = fromEntity.Str14;
            toEntity.Str15 = fromEntity.Str15;
            toEntity.Bool1 = fromEntity.Bool1;
            toEntity.Bool2 = fromEntity.Bool2;
            toEntity.Bool3 = fromEntity.Bool3;
            toEntity.Bool4 = fromEntity.Bool4;
            toEntity.Int1 = fromEntity.Int1;
            toEntity.Int2 = fromEntity.Int2;
            toEntity.Int3 = fromEntity.Int3;
            toEntity.Int4 = fromEntity.Int4;
            toEntity.Int5 = fromEntity.Int5;
            toEntity.Double1 = fromEntity.Double1;
            toEntity.Double2 = fromEntity.Double2;
            toEntity.Double3 = fromEntity.Double3;
            toEntity.Double4 = fromEntity.Double4;

            MapVirtualFields(fromEntity.Id, toEntity.Id);
        }

        private void MapVirtualFields(Guid fromEntityId, Guid toEntityId)
        {
            //依据配置返回
            var bodyFields_from = _contentBodyRepository.GetAllList(c => c.ContentId == fromEntityId);
            var bodyFields_to = _contentBodyRepository.GetAllList(c => c.ContentId == toEntityId);
            foreach (var field in bodyFields_from.Where(p => !bodyFields_to.Select(c => c.FieldName).Contains(p.FieldName)))
            {
                var item = new ContentBody { ContentId = toEntityId, FieldName = field.FieldName, Value = field.Value };
                _contentBodyRepository.Insert(item);
            }
            foreach (var field in bodyFields_to)
            {
                var item = bodyFields_from.FirstOrDefault(c => c.FieldName == field.FieldName);
                if (item == null)
                {
                    _contentBodyRepository.Delete(field);
                }
                else
                {
                    field.Value = item.Value;
                }
            }

            var fields_from = _contentFieldRepository.GetAllList(c => c.ContentId == fromEntityId);
            var fields_to = _contentFieldRepository.GetAllList(c => c.ContentId == toEntityId);
            foreach (var field in fields_from.Where(p => !fields_to.Select(c => c.FieldName).Contains(p.FieldName)))
            {
                var item = new ContentField { ContentId = toEntityId, FieldName = field.FieldName, Value = field.Value };
                _contentFieldRepository.Insert(item);
            }
            foreach (var field in fields_to)
            {
                var item = fields_from.FirstOrDefault(c => c.FieldName == field.FieldName);
                if (item == null)
                {
                    _contentFieldRepository.Delete(field);
                }
                else
                {
                    field.Value = item.Value;
                }
            }
        }
        
        #endregion
    }
}
